package com.hunter.api.help;

import java.nio.charset.Charset;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import lombok.extern.slf4j.Slf4j;

/**
 * AESHelper
 * AES加密算法
 *
 * @author CheneyZhao
 * @date 2018/9/12 11:06
 * @version 1.0
 */
@Slf4j
public class AESHelper {
    private static Charset charset = Charset.forName("UTF-8");

    private static byte[] ecbNoPadding(byte[] data, String key, boolean isEncrypt) {
        byte[] out = null;
        //key 处理为16位
        byte[] keyBytes = ByteHelper.decodeBase64(generateKey(key));
        try {
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
            //算法/模式/补码方式
            Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
            cipher.init(isEncrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, keySpec);
            if (isEncrypt) {
                //分块加密
                int blockCount = data.length / 16 + 1;
                out = new byte[blockCount * 16];
                int i = 0;
                while (i < blockCount) {
                    //计算偏移
                    int offset = i * 16;
                    //计算剩余长度
                    int len = (data.length - 16 - offset) > 0 ? 16 : (data.length - offset);
                    byte[] input = new byte[16];
                    System.arraycopy(data, offset, input, 0, len);
                    byte[] output = cipher.doFinal(input);
                    System.arraycopy(output, 0, out, offset, 16);
                    i++;
                }
            } else {
                out = cipher.doFinal(data);
            }
        } catch (Exception e) {
            log.error("aesECB - error: " + e.getLocalizedMessage());
        }
        return out;
    }

    /**
     * 根据提供的原始key，生成实际加密/解密用的key(base64编码)
     * @param encyKey 原始key
     * @return 实际加密/解密用的的key
     */
    public static String generateKey(String encyKey) {
        KeyGenerator kgen;
        try {
            kgen = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
            secureRandom.setSeed(encyKey.getBytes(charset));
            kgen.init(128, secureRandom);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            return ByteHelper.encodeBase64(enCodeFormat);
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
        }
        return null;
    }

    /**
     * 用指定key，对 byte数组data进行加密
     *
     * @param data 需要加密的byte数组
     * @param key  加密用的key，字符串
     * @return 加密后的byte数组
     */
    public static byte[] encrypt(byte[] data, String key) {
        return ecbNoPadding(data,key,true);
    }

    /**
     * 加密指定字符串，加密结果用base64编码
     * @param data 要加密的字符串
     * @param key 秘钥
     * @return base64编码的加密结果
     */
    public static String encrypt(String data, String key) {
        byte[] dataBytes = data.getBytes(charset);
        return ByteHelper.encodeBase64(ecbNoPadding(dataBytes,key,true));
    }
    /**
     * 加密指定字符串，加密结果用base64编码
     * @param data 要加密的字符串
     * @param key 秘钥
     * @return base64编码的加密结果
     */
    public static String encrypt(String data, String key,boolean isEncrypt) {
        byte[] dataBytes = data.getBytes(charset);
        return ByteHelper.encodeBase64(ecbNoPadding(dataBytes,key,isEncrypt));
    }

    /**
     * 用指定key，对data进行解密，
     *
     * @param data 需要解密的byte数组
     * @param key  加密用的key，字符串
     * @return 解密后的byte数组
     */
    public static byte[] decrypt(byte[] data, String key) {
        return ecbNoPadding(data,key,true);
    }

    /**
     * 用指定key，对data进行解密，
     *
     * @param data 需要解密的byte数组
     * @param key  加密用的key，字符串
     * @return 解密后的byte数组
     */
    public static byte[] decrypt(byte[] data, String key,boolean isEncrypt) {
        return ecbNoPadding(data,key,isEncrypt);
    }

    /**
     * 解密指定字符串（base64编码过的）
     * @param base64Data 要解密的字符串，base64编码的
     * @param key 秘钥
     * @return 解密后的字符串，utf-8编码
     */
    public static String decrypt(String base64Data, String key) {
        byte[] data=ByteHelper.decodeBase64(base64Data);
        return StringHelper.bytes2Str(ecbNoPadding(data,key,false),charset.name());
    }

    /**
     * 解密指定字符串（base64编码过的）
     * @param base64Data 要解密的字符串，base64编码的
     * @param key 秘钥
     * @return 解密后的字符串，utf-8编码
     */
    public static String decrypt(String base64Data, String key,boolean isEncrypt) {
        byte[] data=ByteHelper.decodeBase64(base64Data);
        return StringHelper.bytes2Str(ecbNoPadding(data,key,isEncrypt),charset.name());
    }
}
